Texto en cursiva, negrita o cursiva negrita.
Hermoso es mejor que feo. Explícito es mejor que implícito. Simple es mejor que complejo. Complejo es mejor que complicado. Plano es mejor que anidado. Escaso es mejor que denso. Cuenta la legibilidad. Los casos especiales no son lo suficientemente especial como para romper las reglas. Aunque sentido práctico supera pureza. Los errores nunca debe pasar en silencio. A menos que explícitamente silenciados. Ante la ambigüedad, rechaza la tentación de adivinar. Debería haber una - y preferiblemente sólo una - manera obvia de hacerlo. Aunque esa manera puede no ser obvia al principio a menos que seas holandés. Ahora es mejor que nunca. Aunque nunca es a menudo mejor que la justo ahora. Si la implementación es difícil de explicar, es una mala idea. Si la implementación es fácil de explicar, puede ser una buena idea. Namespaces son una gran idea de fanfarria - Vamos a hacer más de esos!
Zen de Python
Puedes escribir código que no se ejecutará:
def f(x):
"""Calcula el cuadrado de un número"""
return x**2
O
def f(x):
"""Calcula el cuadrado de un número"""
return x**2
Otro ejemplo en C
if (i=0; i<n; i++) {
printf("hello %d\n", i);
x += 4;
}
O
if (i=0; i<n; i++) {
printf("hello %d\n", i);
x += 4;
}
Los nombres de las variables en Python pueden contener los caracteres a-z
, A-Z
, 0-9
y algunos caracteres especiales como _
. Los nombres de variables normales deben comenzar con una letra.
Por convención, los nombres de las variables comienzan con letra minúscula, mientras que los nombres de las clases comienzan con una letra mayúscula.
Además, existen algunos palabras claves Python que no pueden ser usados como nombres de variables. Éstas son:
and, as, assert, break, class, continue, def, del, elif, else, except,
exec, finally, for, from, global, if, import, in, is, lambda, not, or,
pass, print, raise, return, try, while, with, yield
Nota: Atención con la palabra lambda
, que podría fácilmente ser un nombre de variable natural en un programa científico. Sin embargo, como es una palabra clave, no puede ser usado como nombre de una variable.
El operador para asignar valores en Python es el signo igual (=
). Python es un lenguage de escritura dinámica, de modo que no necesitamos especificar el tipo de una variable cuando la creamos.
Al asignar un valor a una variable nueva se crea esa variable:
In [4]:
# asignaciones de variables
x = 1.0
mi_variable = 12.2
Aunque no se especifique explícitamente, cada variable sí tiene un tipo asociada a ella. El tipo es extraido del valor que le fue asignado.
In [5]:
type(x)
Out[5]:
Si asignamos un nuevo valor a una variable, su tipo puede cambiar.
In [6]:
x = 1
In [7]:
type(x)
Out[7]:
Si tratamos de unsar una variable que no ha sido definida obtenemo un mensaje de error (NameError
):
In [8]:
print(y)
In [9]:
# enteros
x = 1
type(x)
Out[9]:
In [10]:
# flotantes
x = 1.0
type(x)
Out[10]:
In [11]:
# booleanos
b1 = True
b2 = False
type(b1)
Out[11]:
In [12]:
# números complejos: note que se usa `j` para especificar la parte imaginaria
x = 1.0 - 1.0j
type(x)
Out[12]:
In [13]:
print(x)
In [14]:
print(x.real, x.imag)
In [15]:
import types
# imprime todos los tipos definidos en el módulo `types`
print(dir(types))
In [16]:
x = 1.0
# verifica si la variable x es flotante
type(x) is float
Out[16]:
In [17]:
# verifica si la variable x es un entero
type(x) is int
Out[17]:
Podemos también usar el método isinstance
para testear tipos de variables:
In [18]:
isinstance(x, float)
Out[18]:
In [19]:
x = 1.5
print(x, type(x))
In [20]:
x = int(x)
print(x, type(x))
In [21]:
z = complex(x)
print(z, type(z))
In [22]:
x = float(z)
Un número complejo no puede ser convertido a un número flotante o a un entero. Necesitamos usar z.real
, o bien z.imag
, para extraer la parte que deseamos del número complejo z:
In [23]:
y = bool(z.real)
print(z.real, " -> ", y, type(y))
y = bool(z.imag)
print(z.imag, " -> ", y, type(y))
In [24]:
1 + 2, 1 - 2, 1 * 2, 1 / 2
Out[24]:
In [25]:
1.0 + 2.0, 1.0 - 2.0, 1.0 * 2.0, 1.0 / 2.0
Out[25]:
In [26]:
# División entera de dos númenos flotantes
3.0 // 2.0
Out[26]:
In [27]:
# Atención! El operador de potencia en Python no es ^, sino **
2 ** 2
Out[27]:
and
, not
, or
.
In [28]:
True and False
Out[28]:
In [29]:
not False
Out[29]:
In [30]:
True or False
Out[30]:
>
, <
, >=
(mayor o igual), <=
(menor o igual), ==
igualdad, es
identico.
In [31]:
2 > 1, 2 < 1
Out[31]:
In [32]:
2 > 2, 2 < 2
Out[32]:
In [33]:
2 >= 2, 2 <= 2
Out[33]:
In [34]:
# igualdad
[1,2] == [1,2]
Out[34]:
In [35]:
# ¿objetos identicos?
l1 = l2 = [1,2]
l1 is l2
Out[35]:
In [36]:
s = "Hola mundo"
type(s)
Out[36]:
In [37]:
# longitud de la cadena: el número de caracteres que contiene
len(s)
Out[37]:
In [38]:
# reemplaza una subcadena de una cadena por cadena
s2 = s.replace("mundo", "universo")
print(s2)
Podemos aislar un carácter en una cadena usando []
:
In [39]:
s[0]
Out[39]:
Atención usuarios de MATLAB: el indexado comienza en 0!
Podemos extraer una parte de una cadena usando la sintaxis [desde:hasta]
, que extrae caracteres entre los índices desde
y hasta
:
In [40]:
s[0:5]
Out[40]:
Si omitimos desde
o bien hasta
de [desde:hasta]
, por defecto se entiende que se refiere al comienzo y/o al fin de la cadena, respectivamente:
In [41]:
s[:5]
Out[41]:
In [42]:
s[6:]
Out[42]:
In [43]:
s[:]
Out[43]:
Podemos también definir el tamaño del paso usando la sintaxis [desde:hasta:paso]
(el valor por defecto de paso
es 1, como ya vismo):
In [44]:
s[::1]
Out[44]:
In [45]:
s[::2]
Out[45]:
Esta técnica es llamada slicing ("rebanado"). Puede leer más sobre la sintaxis aquí http://pyspanishdoc.sourceforge.net/lib/built-in-funcs.html y aquí (en inglés) http://docs.python.org/release/2.7.3/library/functions.html?highlight=slice#slice
Python tiene un rico conjunto de funciones para procesar texto. Ver por ejemplo http://docs.python.org/2/library/string.html (en inglés) para más información.
In [46]:
print("uno", "dos", "tres") # El comando print puede desplegar varias cadenas
In [47]:
print("uno", 1.0, False, -1j) # El comendo print convierte todos los argumentos a cadenas
In [48]:
print("uno" + "dos" + "tres") # cadenas "sumadas" con + son contatenadas sin espacio entre ellas
In [49]:
print("valor = %f" % 1.0) # podemos usar formateo de cadenas en el estilo del lenguaje C
In [50]:
# este formateo crea una cadena
s2 = "valor1 = %.2f. valor2 = %d" % (3.1415, 1.5)
print(s2)
In [51]:
# forma alternativa, más intuitiva para formatear una cadena
s3 = 'valor1 = {0}, valor2 = {1}'.format(3.1415, 1.5)
print(s3)
In [52]:
l = [1,2,3,4]
print(type(l))
print(l)
Podemos usar las mismas técnicas de "rebanado" que usamos en el caso de cadenas para manipular listas:
In [53]:
print(l)
print(l[1:3])
print(l[::2])
Atención usuarios de MATLAB: el indexado comienza en 0!
In [54]:
l[0]
Out[54]:
Los elementos en una lista no requieren ser del mismo tipo:
In [55]:
l = [1, 'a', 1.0, 1-1j]
print(l)
Las listas en Python pueden ser inhomogéneas y arbitrariamente anidadas:
In [56]:
lista_anidada = [1, [2, [3, [4, [5]]]]]
lista_anidada
Out[56]:
Las listas juegan un rol muy importante en Python y son, por ejemplo, usadas en bucles y otras estructuras de control de flujo (discutidas más abajo). Existan muchas funciones convenientes para generar listas de varios tipos, por ejemplo la función range
:
In [57]:
desde = 10
hasta = 30
paso = 2
range(desde, hasta, paso)
Out[57]:
In [58]:
# en Python 3 range genera un interador, que puede ser convertido a una lista usando 'list(...)'. Esto no tiene efecto en Python 2
list(range(desde, hasta, paso))
Out[58]:
In [59]:
list(range(-10, 10))
Out[59]:
In [60]:
s
Out[60]:
In [61]:
# convierte una cadena a una lista, por conversión de tipo:
s2 = list(s)
s2
Out[61]:
In [62]:
# ordenando listas
s2.sort()
print(s2)
In [63]:
# crea una nueva lista vacía
l = []
# agrega un elemento usando `append`
l.append("A")
l.append("d")
l.append("d")
print(l)
Podemos modificar listas asignando nuevos valores a los elementos de la lista. En lenguaje técnico se dice que la lista es mutable.
In [64]:
l[1] = "p"
l[2] = "p"
print(l)
In [65]:
l[1:3] = ["d", "d"]
print(l)
Insertar un elemento en una posición específica insert
In [66]:
l.insert(0, "i")
l.insert(1, "n")
l.insert(2, "s")
l.insert(3, "e")
l.insert(4, "r")
l.insert(5, "t")
print(l)
Eliminar el primer elemento con un valor específico usando 'remove'
In [67]:
l.remove("A")
print(l)
Eliminar un elemento en una posición específica usando del
:
Puede introducir help(list)
para más detalles, o leer la documentación en la red
In [68]:
punto = (10, 20)
print(punto, type(punto))
In [69]:
punto = 10, 20
print(punto, type(punto))
Podemos separar una tupla asignandola a una lista de variables separadas por coma:
In [70]:
x, y = punto
print("x =", x)
print("y =", y)
Si intentamos asignar un nuevo valor a un elemento de una tupla obtenemos un error:
In [71]:
punto[0] = 20
In [72]:
parametros = {"parametro1" : 1.0,
"parametro2" : 2.0,
"parametro3" : 3.0,}
print(type(parametros))
print(parametros)
In [73]:
print("parametro1 = " + str(parametros["parametro1"]))
print("parametro2 = " + str(parametros["parametro2"]))
print("parametro3 = " + str(parametros["parametro3"]))
In [74]:
parametros["parametro1"] = "A"
parametros["parametro2"] = "B"
# agrega una nueva entrada
parametros["parametro4"] = "D"
print("parametro1 = " + str(parametros["parametro1"]))
print("parametro2 = " + str(parametros["parametro2"]))
print("parametro3 = " + str(parametros["parametro3"]))
print("parametro4 = " + str(parametros["parametro4"]))
In [75]:
afirmacion1 = False
afirmacion2 = False
if afirmacion1:
print("afirmacion1 es verdadera")
elif afirmacion2:
print("afirmacion2 es verdadera")
else:
print("afirmacion1 y afirmacion2 son falsas")
Aquí encontramos por primera un aspecto pecular e inusual del lenguaje Python: Los bloques del programa son definidos por su nivel de indentación (la cantidad de espacio antes de cada linea).
Compare con el código equivalente en C:
if (afirmacion1)
{
printf("afirmacion1 es verdadera\n");
}
else if (afirmacion2)
{
printf("afirmacion1 es verdadera\n");
}
else
{
printf("afirmacion1 y afirmacion2 son falsas\n");
}
En C los bloques son definidos por los paréntesis llaves {
y }
. El nivel de indentación (espacio en blanco antes del código) no importa (es completamente opcional).
En Python, la extensión de un bloque de código es definido por el nivel de indentación (usualmente un tab o cuatro espacios en blanco). Esto significa que debemos ser cuidados@s de indentar nuestro código correctamente, de lo contrario tendremos errores de sintaxis.
Ejemplos:
In [76]:
afirmacion1 = afirmacion2 = True
if afirmacion1:
if afirmacion2:
print("tanto afirmacion1 como afirmacion2 son verdaderas")
In [77]:
# Mala indentación!
if afirmacion1:
if afirmacion2:
print("tanto afirmacion1 como afirmacion2 son verdaderas") # esta línea está mal indentada
In [78]:
afirmacion1 = False
if afirmacion1:
print("afirmacion1 es verdadera")
print("aun estamos dentro del bloque if")
In [79]:
if afirmacion1:
print("afirmacion1 es verdadera")
print("ahora estamos fuera del bloque")
In [80]:
for x in [1,2,3]:
print(x)
El ciclo for
itera sobre los elementos de la lista suministrada y ejecuta el bloque suministrado una vez para cada elemento. Cualquier tipo de lista puede ser usada para un ciclo for
. Por ejemplo:
In [81]:
for x in range(4): # por defecto range comienza con 0
print(x)
Nota: range(4)
no incluye el 4 !
In [82]:
for x in range(-3,3):
print(x)
In [83]:
for palabra in ["computación", "científica", "con", "Python"]:
print(palabra)
Para iterar sobre pares clave-valor en un diccionario:
In [84]:
for clave, valor in parametros.items():
print(clave + " = " + str(valor))
Algunas veces es útil tener acceso a los índices de los valores mientras se itera sobre una lista. Podemos usar la función enumerate
para esto:
In [85]:
for idx, x in enumerate(range(-3,3)):
print(idx, x)
Listas: Creando listas usando ciclos for
:
Una forma conveniente y compacta de inicializar listas:
In [86]:
l1 = [x**2 for x in range(0,5)]
print(l1)
Ciclos while
:
In [87]:
i = 0
while i < 5:
print(i)
i = i + 1
print("listo")
Note que el comando print("listo")
no es parte del cuerpo del ciclo while
, debido a su indentación.
In [88]:
def func0():
print("test")
In [89]:
func0()
En forma opcional, pero muy recomendada, podemos definir un "docstring", que es una descripción del propósito y comportamiento de la función. El docstring debería ser incluido directamente después de la definición de la función, antes del código en el cuerpo de la función.
In [90]:
def func1(s):
"""
Imprime la cadena 's' y dice cuántos caracteres tiene
"""
print(s + " tiene " + str(len(s)) + " caracteres")
In [91]:
help(func1)
In [92]:
func1("test")
Funciones que retornan un valor usan la palabra clave return
:
In [93]:
def cuadrado(x):
"""
Calcula el cuadrado de x.
"""
return x**2
In [94]:
cuadrado(4)
Out[94]:
Podemos retornar múltiples valores desde una función usando las tuplas (ver más arriba):
In [96]:
def potencias(x):
"""
Calcula algunas potencias de x.
"""
return x**2, x**3, x**4
In [97]:
potencias(3)
Out[97]:
In [98]:
x2, x3, x4 = potencias(3)
print(x3)
In [99]:
def mifunc(x, p=2, debug=False):
if debug:
print("evaluando mifunc para x = " + str(x) + " usando el exponente p = " + str(p))
return x**p
Si no suministramos un valor para el argumento debug
al llamar a la función mifunc
se considera el valor definido por defecto:
In [100]:
mifunc(5)
Out[100]:
In [101]:
mifunc(5, debug=True)
Out[101]:
Si listamos explícitamente el nombre de los argumentos al llamar una función, ellos no necesitan estar en el mismo orden usando en la definición de la función. Esto es llamado argumentos de palabra clave (keyword), y son a menudo muy útiles en funciones que requieren muchos argumentos opcionales.
In [102]:
mifunc(p=3, debug=True, x=7)
Out[102]:
In [103]:
f1 = lambda x: x**2
# es equivalente a
def f2(x):
return x**2
In [104]:
f1(2), f2(2)
Out[104]:
Esta técnica es útil, por ejemplo, cuando queremos pasar una función simple como argumento de otra función, como en este caso:
In [105]:
# map es una función predefinida en Python
map(lambda x: x**2, range(-3,4))
Out[105]:
In [106]:
# in Python 3 podemos usar `list(...)` para convertir la iteración a una lista explícita
list(map(lambda x: x**2, range(-3,4)))
Out[106]:
Las clases son una característica clave de la programación orientada al objeto. Una clase es una estructura para representar un objeto y las operaciones que pueden ser realizadas sobre el objeto.
En Python una clase puede contener atributos (variables) y métodos (funciones).
En Python una clase es definida casi como una función, pero usando la palabra clave class
, y la definición de la clase usualmente contiene algunas definiciones de métodos (una función en una clase).
Cada método de una clase debería tener un argumento self
como su primer argumento. Este objeto es una autoreferencia.
Algunos nombres de métodos de clases tienen un significado especial, por ejemplo:
__init__
: El nombre del método que es invocado cuando el objeto es creado por primera vez.__str__
: Un método que es invocado cuando se necesita una simple representación de cadena de la clase, como por ejemplo cuando se imprime.
In [107]:
class Punto:
"""
Clase simple para representar un punto en un sistema de coordenadas cartesiano.
"""
def __init__(self, x, y):
"""
Crea un nuevo punto en x, y.
"""
self.x = x
self.y = y
def traslada(self, dx, dy):
"""
Traslada el punto en dx y dy en las direcciones x e y respectivamente.
"""
self.x += dx
self.y += dy
def __str__(self):
return("Punto en [%f, %f]" % (self.x, self.y))
Para crear una nuva instancia de una clase:
In [108]:
p1 = Punto(0, 0) # eso invoca el método __init__ en la cláse Punto
print(p1) # esto invoca el método __str__
Para invocar un método en la instancia de clase p
:
In [109]:
p2 = Punto(1, 1)
p1.traslada(0.25, 1.5)
print(p1)
print(p2)
Note que llamar a métodos de clases puede modificar el estado de esa instancia de clase particular, pero no afecta otras instancias de la clase o alguna otra variable global.
Esto es una de las cosas buenas de un diseño orientado al objeto: código como las funciones y variables relacionadas son agrupadas en entidades separadas e independientes.
La mayoría de la funcionalidad en Python es provista por módulos. La Librería Estándar de Python es una gran colección de módulos que proveen implementaciones multiplataforma de recursos tales como el acceso al sistema operativo, entrada/salido de archivos (file I/O), manejo de cadenas, comunicación en redes, y mucho más.
Para usar un módulo en un programa Python éste debe primero ser importado. Un módulo puede ser importado usando el comando import
. Por ejemplo, para importar el módulo math
, que contiene muchas funciones matemáticas estándar, podemos usar:
In [110]:
import math
Esto incluye el módulo completo y lo deja disponible para su uso en el programa. Por ejemplo, podemos escribir:
In [111]:
import math
x = math.cos(2 * math.pi)
print(x)
Alternativamente, podemos elegir importar todos los símbolos (funciones y variables) en un módulo al espacio de nombres (namespace) actual (de modo que no necesitemos usar el prefijo "math.
" cada vez que usemos algo del módulo math
:
In [112]:
from math import *
x = cos(2 * pi)
print(x)
Esta forma de proceder puede ser muy conveniente, pero en programas largos que incluyen muchos módulos es a menudo una buena idea mantener los símbolos de cada módulo en sus propios espacios de nombres, usando import math
. Esto elimina potenciales confusiones con eventuales colisiones de nombres.
Como una tercera alternativa, podemos importar sólo algunos símbolos seleccionados desde un módulo listando explícitamente aquellos símbolos que deseamos importar, en lugar de usar el carácter comodín *
:
In [113]:
from math import cos, pi
x = cos(2 * pi)
print(x)
Luego que se ha cargado un módulo, podemos listar los símbolos que éste provee usando la función dir
:
In [114]:
import math
dir(math)
Out[114]:
Usando la función help
podemos obtener una descripción de cada función (casi... no todas las funciones tienen docstrings, como se les llama técnicamente. Sin embargo, la mayoría de las funciones están documentadas de esta forma).
In [115]:
help(math.log)
In [116]:
log(10) # calcula el logaritmo de 10 en base e
Out[116]:
In [117]:
log(10, 2) # calcula el logaritmo de 10 en base 2
Out[117]:
También podemos usar la función help
directamente sobre los módulos:
help(math)
Algunos módulos muy útiles de la librería estándar de Python son os
(interfaz con el sistema operativo), sys
(Parámetros y funciones específicas del sistema), math
(funciones matem'aticas), shutil
(operaciones con archivos), subprocess
, multiprocessing
, threading
.
Una lista completa de los módulos estándar para Python 2 y Python 3 está disponible (en inglés) en http://docs.python.org/2/library/ y http://docs.python.org/3/library/, respectivamente. Una versión en español está disponible en http://pyspanishdoc.sourceforge.net/lib/lib.html.
Uno de los conceptos más importantes en programación es el de reusar código para evitar repeticiones.
La idea es escribir funciones y clases con un propósito y extensión bien definidos, y reusarlas en lugar de repetir código similar en diferentes partes del programa (programación modular). Usualmente el resultado es que se mejora ostensiblemente la facilidad de lectura y de mantención de un programa. En la práctica, esto significa que nuestro programa tendrá menos errores, y serán más fáciles de extender y corregir.
Python permite programación modular en diferentes niveles. Las funciones y las clases son ejemplos de herramientas para programación modular de bajo nivel. Los módulos Python son construcciones de programación modular de más alto nivel, donde podemos colectar variables relacionadas, funciones y clases. Un módulo Python es definido en un archivo Python (con extensión .py
), y puede ser accequible a otros módulos Python y a programas usando el comendo import
.
Considere el siguiente ejemplo: el archivo mimodulo.py
contiene una implementación simple de una variable, una función y una clase:
In [119]:
%more mimodulo.py
Podemos importar el módulo mimodulo
a un programa Python usando import
:
In [120]:
import mimodulo
Use help(module)
para obtener un resumen de lo que suministra el módulo:
In [121]:
help(mimodulo)
In [122]:
mimodulo.mi_variable
Out[122]:
In [123]:
mimodulo.mi_function()
Out[123]:
In [124]:
mi_clase = mimodulo.MiClase()
mi_clase.set_variable(10)
mi_clase.get_variable()
Out[124]:
En Python los errores son manejados con una construcción especial de lenguaje llamada "Exceptions" (excepciones). Cuando ocurre un error, una excepción puede ser hecha, que interrumpe el flujo normal del programa y retorna a algún otro lugar del código donde se definan los comandos try-except más cercanos.
Para generar una excepción podemos usar el comando raise
, que toma un argumento que debe ser una instancia de la clase BaseExpection
o una clase derivada de ella.
In [126]:
raise Exception("descripción del error")
Un úso típico de las excepciones es para abortar funciones cuando ocurre algún error, por ejemplo:
def mi_funcion(argumentos):
if not verify(argumentos):
raise Expection("Argumentos invalidos")
# el resto del código sigue aquí
Para capturar los errores que son generados por funciones y métodos de clases, o por el mismo intérprete Python, use los comandos try
y except
:
try:
# aquí va el código normal
except:
# el código para manejar el error va aquí
# Este código no se ejecuta a menos que
# el código de arriba genere un error
Por ejemplo:
In [127]:
try:
print("test")
# genera un error: ya que la variable test no está definida
print(test)
except:
print("Encontré una excepción")
Para obtener información sobre un error, podemos accesar la instancia de clase Exception
que describe la excepción usando por ejemplo:
except Exception as e:
In [128]:
try:
print("test")
# genera un error: ya que la variable test no está definida
print(test)
except Exception as e:
print("Encontré una excepción:" + str(e))
In [129]:
# Esta celda da el estilo al notebook
from IPython.core.display import HTML
css_file = './css/aeropython.css'
HTML(open(css_file, "r").read())
Out[129]: